/*----------------------------------------------------------------------------
 * Copyright (c) <2013-2015>, <Huawei Technologies Co., Ltd>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *---------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
 * Notice of Export Control Law
 * ===============================================
 * Huawei LiteOS may be subject to applicable export control laws and regulations, which might
 * include those applicable to Huawei LiteOS of U.S. and the country in which you are located.
 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such
 * applicable export control laws and regulations.
 *---------------------------------------------------------------------------*/

#include "los_typedef.h"
#include "jffs2_type.h"
#include "fileio.h"
#include "errno.h"
#include "fcntl.h"
#include "sys/stat.h"
#undef mode_t

#include "stdlib.h"
#include "vfs_jffs2.h"
#include "jffs2_config.h"
#include "porting.h"
#include <string.h>
#include "los_mux.h"
#include "inode/inode.h"
#include "sys/statfs.h"
#include "fs/dirent_fs.h"
#include "fs/fs.h"
#include "los_tables.h"
#include "linux/mtd/mtd.h"
#include "linux/mtd/mtd_list.h"

#ifdef LOSCFG_FS_JFFS

#if DEVICE_PART_MAX > 1
    #error "support only one jffs2 partition on a flash device!"
#endif


UINT32 jffs2_lock;
struct jffs2_mtab_entry * mte[CONFIG_MTD_PATTITION_NUM];
static const char jffs2_root_path[] = ".";

int jffs2_result_to_vfs(int result)
{
    if (result >0)
        result = -result;
    return result;
}

struct inode * jffs_block[CONFIG_MTD_PATTITION_NUM];
static int vfs_jffs_bind(FAR struct inode *blkdriver, FAR const void *data,
        FAR void **handle, FAR const char *relpath)
{
    int result;
    mtd_partition * p = (mtd_partition *)blkdriver->i_private;
    int partition_num = p->patitionnum;
    struct mtd_info *mtd = (struct mtd_info *)(p->mtd_info);
    /* find a empty entry in partition table */
    if (mtd == NULL)
    {
        return -EINVAL;
    }
    if (mtd->type != MTD_NORFLASH)
    {
        return -EINVAL;
    }

    mte[partition_num] = (jffs2_mtab_entry *)malloc(sizeof(struct jffs2_mtab_entry));
    if (mte[partition_num] == NULL)
    {
        return -ENOMEM;
    }
    mte[partition_num]->fs=(jffs2_fstab_entry*)malloc(sizeof(struct jffs2_fstab_entry));
    if (mte[partition_num]->fs == NULL)
    {
        free(mte[partition_num]);
        mte[partition_num] = NULL;
        return -ENOMEM;
    }

    mte[partition_num]->fsname = "jffs2";
    mte[partition_num]->devname = NULL;

    /* note that, i use mte->data to store rtt's device
     * while, in jffs2_mount, mte->data will be copy into
     * s_dev in struct super_block, and mte->data will be
     * filled with jffs2_sb(see the source of jffs2_mount.
     */
    //mte->data = (JFFS2_ADDRWORD)fs->dev_id;
    /* after jffs2_mount, mte->data will not be dev_id any more */
    result = jffs2_fste.mount(NULL, mte[partition_num], partition_num);
    if (result != 0)
    {
        free(mte[partition_num]->fs);
        mte[partition_num]->fs = NULL;
        free(mte[partition_num]);
        mte[partition_num] = NULL;
        return jffs2_result_to_vfs(result);
    }
    *handle = (void*)p;
    jffs_block[partition_num] = blkdriver;
    return 0;
}

static int  vfs_jffs_unbind(FAR void *handle, FAR struct inode **blkdriver)
{
    int result;
    mtd_partition * p = (mtd_partition *)handle;
    int partition_num = p->patitionnum;
    result = jffs2_fste.umount(mte[partition_num]);
    if (result)
        return jffs2_result_to_vfs(result);
    free(mte[partition_num]->fs);
    mte[partition_num]->fs = NULL;
    free(mte[partition_num]);
    mte[partition_num] = NULL;
    free(p->mountpoint_name);
    p->mountpoint_name = NULL;
    *blkdriver = jffs_block[partition_num];
    return 0;
}

static int vfs_jffs_open(FAR struct file *filep, FAR const char *relpath,
        int oflags, mode_t mode)
{
    int result;
    int jmode,partition_num;
    const char * name = (const char *)NULL;
    jffs2_sfile *jffs2_file = (jffs2_sfile *)NULL;
    mtd_partition * p = (mtd_partition *)NULL;

    p = (mtd_partition *)filep->f_inode->i_private;
    partition_num = p->patitionnum;
    jffs2_file = malloc(sizeof(jffs2_sfile));
    if (jffs2_file == NULL)
    {
        return -ENOMEM;
    }
    name=relpath;
    if ((name[0] == '/') && (name[1] == 0))
        name = jffs2_root_path;
    else if(name[0] == '/')/* name[0] still will be '/' */
        name ++;

    if(filep->f_inode->mountflags == MS_RDONLY && oflags != O_RDONLY)
    {
        free(jffs2_file);
        return -EACCES;
    }

    if (oflags & O_DIRECTORY) /* operations about dir */
    {
        free(jffs2_file);
        return -EACCES;
    }

    /* regular file operations */

    jmode=0;
    if ((oflags & O_ACCMODE) == O_RDONLY) jmode |= JFFS2_O_RDONLY;
    if (oflags & O_WRONLY) jmode |= JFFS2_O_WRONLY;
    if (oflags & O_RDWR)   jmode |= JFFS2_O_RDWR;
    /* Opens the file, if it is existing. If not, a new file is created. */
    if (oflags & O_CREAT) jmode |= JFFS2_O_CREAT;
    /* Creates a new file. If the file is existing, it is truncated and overwritten. */
    if (oflags & O_TRUNC) jmode |= JFFS2_O_TRUNC;
    /* Creates a new file. The function fails if the file is already existing. */
    if (oflags & O_EXCL) jmode |= JFFS2_O_EXCL;
    if (oflags & O_APPEND) jmode |= JFFS2_O_APPEND;

    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fste.open(mte[partition_num], 0, name, jmode, mode,jffs2_file);
    if (result != 0)
    {
        jffs_mutex_release(&jffs2_lock);
        free(jffs2_file);
        return jffs2_result_to_vfs(result);
    }
    /* save this pointer, it will be used when calling read(),write(),
       flush(), lessk(), and will be free when calling close()*/
    filep->f_priv= jffs2_file;
    filep->f_pos = jffs2_file->f_offset;
    jffs_mutex_release(&jffs2_lock);
    return 0;
}

static int vfs_jffs_close(FAR struct file *filep)
{
    int result;
    jffs2_sfile * jffs2_file = (jffs2_sfile *)NULL;

    JFFS_ASSERT(filep->f_priv != NULL);
    jffs2_file = (jffs2_sfile *)(filep->f_priv);

    if ((unsigned int)(filep->f_oflags) & O_DIRECTORY) /* operations about dir */
    {
        jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
        result = jffs2_dirops.fo_close(jffs2_file);
        jffs_mutex_release(&jffs2_lock);
        if (result)
            return jffs2_result_to_vfs(result);
        return 0;
    }
    /* regular file operations */
    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fileops.fo_close(jffs2_file);
    jffs_mutex_release(&jffs2_lock);
    if (result)
    {
        return jffs2_result_to_vfs(result);
    }
    return 0;
}

static ssize_t vfs_jffs_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
{
    jffs2_sfile * jffs2_file = (jffs2_sfile *)NULL;
    struct JFFS2_UIO_TAG uio_s;
    struct JFFS2_IOVEC_TAG iovec;
    int result;

    JFFS_ASSERT(filep->f_priv != NULL);
    jffs2_file = (jffs2_sfile *)(filep->f_priv);
    uio_s.uio_iov = &iovec;
    uio_s.uio_iov->iov_base = buffer;
    uio_s.uio_iov->iov_len = buflen;
    uio_s.uio_iovcnt = 1; //must be 1
    //uio_s.uio_offset //not used...
    uio_s.uio_resid = uio_s.uio_iov->iov_len; //seem no use in jffs2;

    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fileops.fo_read(jffs2_file, &uio_s);
    jffs_mutex_release(&jffs2_lock);
    if (result)
        return jffs2_result_to_vfs(result);

    /* update position */
    filep->f_pos= (loff_t)jffs2_file->f_offset;
    return uio_s.uio_iov->iov_len - uio_s.uio_resid;
}

static ssize_t vfs_jffs_write(FAR struct file *filep, FAR const char *buffer,
        size_t buflen)
{
    jffs2_sfile * jffs2_file = (jffs2_sfile *)NULL;
    struct JFFS2_UIO_TAG uio_s;
    struct JFFS2_IOVEC_TAG iovec;
    int result;

    if(filep->f_inode->mountflags == MS_RDONLY)
    {
        return -EACCES;
    }

    JFFS_ASSERT(filep->f_priv != NULL);
    jffs2_file = (jffs2_sfile *)(filep->f_priv);
    uio_s.uio_iov = &iovec;
    uio_s.uio_iov->iov_base = (void *)buffer;
    uio_s.uio_iov->iov_len = buflen;
    uio_s.uio_iovcnt = 1; //must be 1

    uio_s.uio_resid = uio_s.uio_iov->iov_len; //seem no use in jffs2;

    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fileops.fo_write(jffs2_file, &uio_s);
    jffs_mutex_release(&jffs2_lock);
    if (result)
    {
        filep->f_pos= (loff_t)jffs2_file->f_offset;
        return jffs2_result_to_vfs(result);
    }
    /* update position */
    filep->f_pos= (loff_t)jffs2_file->f_offset;
    return  uio_s.uio_iov->iov_len -uio_s.uio_resid;
}
static off_t vfs_jffs_seek(FAR struct file *filep, off_t offset, int whence)
{
    jffs2_sfile * jffs2_file = (jffs2_sfile *)NULL;
    int result;
    JFFS_ASSERT(filep->f_priv != NULL);
    jffs2_file = (jffs2_sfile *)(filep->f_priv);

    /* set offset as current offset */
    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fileops.fo_lseek(jffs2_file, &offset, whence);
    jffs_mutex_release(&jffs2_lock);
    if (result)
        return jffs2_result_to_vfs(result);
    /* update file position */
    filep->f_pos = (loff_t)offset;
    return offset;
}

static loff_t vfs_jffs_seek64(FAR struct file *filep, loff_t offset, int whence)
{
    return (loff_t)vfs_jffs_seek(filep, (off_t)offset, whence);
}

static int vfs_jffs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
    PRINT_ERR("%s NOT SUPPORT\n", __FUNCTION__);
    return -ENOSYS;
}

static int vfs_jffs_sync(FAR struct file *filep)
{
    return 0;
}

static int vfs_jffs_dup(FAR const struct file *oldp, FAR struct file *newp)
{
    PRINT_ERR("%s NOT SUPPORT\n", __FUNCTION__);
    return -ENOSYS;
}

static int vfs_jffs_opendir(FAR struct inode *mountpt, FAR const char *relpath,FAR struct fs_dirent_s *dir)
{

    int result;
    jffs2_sfile * jffs2_file = (jffs2_sfile *)NULL;
    mtd_partition * p = (mtd_partition *)mountpt->i_private;
    int partition_num = p->patitionnum;

    jffs2_file = malloc(sizeof(jffs2_sfile));
    if (jffs2_file == NULL)
        return -ENOMEM;

    /* just escape '/' provided by vfs code */

    if ((relpath[0] == '/') && (relpath[1] == 0))
        relpath = jffs2_root_path;
    else if (relpath[0] == '/')/* name[0] still will be '/' */
        relpath ++;

    /* open dir */
    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fste.opendir(mte[partition_num], mte[partition_num]->root, relpath, jffs2_file);
    jffs_mutex_release(&jffs2_lock);
    if (result)
    {
        free(jffs2_file);
        return jffs2_result_to_vfs(result);
    }
#ifdef  CONFIG_JFFS2_NO_RELATIVEDIR
    jffs2_file->f_offset = 2;
#endif
    dir->u.fs_dir = (fs_dir_s)jffs2_file;
    /* save this pointer, it will be used by vfs_jffs2_getdents*/
    return 0;

}

static int vfs_jffs_closedir(FAR struct inode *mountpt,FAR struct fs_dirent_s *dir)
{
    int result;
    jffs2_sfile * jffs2_file = (jffs2_sfile *)NULL;
    jffs2_file = (jffs2_sfile *)dir->u.fs_dir;
    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_dirops.fo_close(jffs2_file);
    jffs_mutex_release(&jffs2_lock);
    if (result)
        return jffs2_result_to_vfs(result);
    return 0;
}

static int vfs_jffs_readdir(FAR struct inode *mountpt,FAR struct fs_dirent_s *dir)
{
    jffs2_sfile * jffs2_file = (jffs2_sfile *)NULL;
    struct JFFS2_UIO_TAG uio_s;
    struct JFFS2_IOVEC_TAG iovec;
    struct jffs2_dirent jffs2_d;
    int result;
    unsigned int min_size;
    unsigned int dst_name_size;

    jffs2_file = (jffs2_sfile *)(dir->u.fs_dir);

    //set jffs2_d
    (void)memset_s(&jffs2_d, sizeof(struct jffs2_dirent), 0, sizeof(struct jffs2_dirent));
    //set JFFS2_UIO_TAG uio_s
    uio_s.uio_iov = &iovec;
    uio_s.uio_iov->iov_base = &jffs2_d;
    uio_s.uio_iov->iov_len = sizeof(struct jffs2_dirent);;
    uio_s.uio_iovcnt = 1; //must be 1
    uio_s.uio_offset = 0;//not used...
    uio_s.uio_resid = uio_s.uio_iov->iov_len; //seem no use in jffs2;

    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_dirops.fo_read(jffs2_file, &uio_s);
    jffs_mutex_release(&jffs2_lock);

    if (result)
        return jffs2_result_to_vfs(result);

    dir->fd_dir.d_off = jffs2_file->f_offset -3;
    dir->fd_dir.d_type = jffs2_d.d_type;
    dir->fd_dir.d_reclen = (uint16_t)sizeof(struct dirent);
    dst_name_size = sizeof(dir->fd_dir.d_name);
    min_size = dst_name_size < sizeof(jffs2_d.d_name) ? dst_name_size : sizeof(jffs2_d.d_name); /*lint !e506*/
    result = strncpy_s(dir->fd_dir.d_name, dst_name_size,jffs2_d.d_name, min_size);
    if(result != EOK)
    {
        return -ENAMETOOLONG;
    }
    dir->fd_dir.d_name[dst_name_size - 1] = '\0';

    return OK;
}

static int vfs_jffs_rewinddir(FAR struct inode *mountpt,FAR struct fs_dirent_s *dir)
{
    int result;
    off_t pos = 0;
    jffs2_sfile *jffs2_file = (jffs2_sfile *)(dir->u.fs_dir);

    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_dirops.fo_lseek(jffs2_file, &pos , SEEK_SET);
    jffs_mutex_release(&jffs2_lock);

    if (result)
        return jffs2_result_to_vfs(result);
    return OK;
}

static int vfs_jffs_mkdir(FAR struct inode *mountpt, FAR const char *relpath,mode_t mode)
{
    int result;
    mtd_partition * p = (mtd_partition *)mountpt->i_private;
    int partition_num = p->patitionnum;
    /* deal path */
    if (relpath[0] == '/')
        relpath++;

    if(mountpt->mountflags == MS_RDONLY)
        return -EACCES;

    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fste.mkdir(mte[partition_num],mte[partition_num]->root,relpath,mode);
    jffs_mutex_release(&jffs2_lock);

    if(result)
        return jffs2_result_to_vfs(result);
    return OK;
}


static int vfs_jffs_rmdir(FAR struct inode *mountpt, FAR const char *relpath)
{
    int result;
    mtd_partition * p = (mtd_partition *)mountpt->i_private;
    int partition_num = p->patitionnum;

    /* deal path */
    if (relpath[0] == '/')
        relpath++;
    else if(relpath[0] == '\0')
        return -EBUSY;

    if(mountpt->mountflags == MS_RDONLY)
        return -EACCES;

    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fste.rmdir(mte[partition_num],mte[partition_num]->root,relpath);
    jffs_mutex_release(&jffs2_lock);

    if(result)
        return jffs2_result_to_vfs(result);
    return OK;
}


static int vfs_jffs_unlink(FAR struct inode *mountpt, FAR const char *relpath)
{
    int result;
    mtd_partition * p = (mtd_partition *)mountpt->i_private;
    int partition_num = p->patitionnum;
    struct jffs2_stat s;
    /* deal path */
    if (relpath[0] == '/')
        relpath++;

    if(mountpt->mountflags == MS_RDONLY)
        return -EACCES;

    /* judge file type, dir is to be delete by rmdir, others by unlink */
    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fste.stat(mte[partition_num], mte[partition_num]->root, relpath, &s);
    if (result)
    {
        jffs_mutex_release(&jffs2_lock);
        return jffs2_result_to_vfs(result);
    }
    switch(s.st_mode & JFFS2_S_IFMT)
    {
        case JFFS2_S_IFREG:
            result = jffs2_fste.unlink(mte[partition_num], mte[partition_num]->root, relpath);
            break;
        case JFFS2_S_IFDIR:
            result = -EISDIR;
            break;
        default:
            /* unknown file type */
            jffs_mutex_release(&jffs2_lock);
            return -1;
    }
    jffs_mutex_release(&jffs2_lock);
    if (result)
        return jffs2_result_to_vfs(result);
    return 0;
}

static int vfs_jffs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath,FAR const char *newrelpath)
{
    int result;
    mtd_partition * p = (mtd_partition *)mountpt->i_private;
    int partition_num = p->patitionnum;
    if (*oldrelpath == '/')
        oldrelpath += 1;
    if (*newrelpath == '/')
        newrelpath += 1;

    if(mountpt->mountflags == MS_RDONLY)
        return -EACCES;

    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fste.rename(mte[partition_num], mte[partition_num]->root, oldrelpath, mte[partition_num]->root, newrelpath);
    jffs_mutex_release(&jffs2_lock);
    if (result)
        return jffs2_result_to_vfs(result);
    return 0;
}



static int vfs_jffs_stat(FAR struct inode *mountpt, FAR const char *relpath,FAR struct stat *buf)
{
    int result;
    struct jffs2_stat s;
    mtd_partition * p = (mtd_partition *)mountpt->i_private;
    int partition_num = p->patitionnum;
    /* deal the path for jffs2 */

    if (relpath[0] == '/')
        relpath++;

    jffs_mutex_take(&jffs2_lock, (UINT32)JFFS_WAITING_FOREVER);
    result = jffs2_fste.stat(mte[partition_num], mte[partition_num]->root, relpath, &s);
    jffs_mutex_release(&jffs2_lock);
    if (result)
        return jffs2_result_to_vfs(result);
    /* convert to vfs stat structure */
    switch(s.st_mode & JFFS2_S_IFMT)
    {
        case JFFS2_S_IFREG:
            buf->st_mode = s.st_mode;//S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
            //S_IWUSR | S_IWGRP | S_IWOTH;
            break;

        case JFFS2_S_IFDIR:
            buf->st_mode = s.st_mode;// S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
            break;

        default:
            buf->st_mode = DT_UNKNOWN; //fixme
            break;
    }

    buf->st_dev  = 0;
    buf->st_size = s.st_size;
    buf->st_mtim.tv_sec= s.sddst_mtime;
    buf->st_mtim.tv_nsec=0;
    buf->st_atim.tv_sec= s.sddst_atime;
    buf->st_atim.tv_nsec=0;
    buf->st_ctim.tv_sec= s.sddst_ctime;
    buf->st_ctim.tv_nsec=0;
    buf->st_blksize = 4096;//fixme: what's this field?
    buf->st_ino=s.st_ino;
    buf->st_gid=0;
    buf->st_uid=0;
    buf->st_nlink=s.st_nlink;
    buf->st_blocks = s.st_size /512;

    return 0;
}

static int vfs_jffs_stat64(FAR struct inode *mountpt, FAR const char *relpath,FAR struct stat64 *buf)
{
    int result;
    struct stat buff;

    result = vfs_jffs_stat(mountpt, relpath, &buff);

    if (!result)
    {
        buf->st_mode = buff.st_mode; //fixme
        buf->st_dev  = 0;
        buf->st_size = (long long)buff.st_size;
        buf->st_mtim.tv_sec= buff.st_mtim.tv_sec;
        buf->st_mtim.tv_nsec=0;
        buf->st_atim.tv_sec= buff.st_atim.tv_sec;
        buf->st_atim.tv_nsec=0;
        buf->st_ctim.tv_sec= buff.st_ctim.tv_sec;
        buf->st_ctim.tv_nsec=0;
        buf->st_blksize = 4096;//fixme: what's this field?
        buf->st_ino = (unsigned long long)buff.st_ino;
        buf->st_gid =  0;
        buf->st_uid = 0;
        buf->st_nlink = buff.st_nlink;
        buf->st_blocks = (long long)buff.st_blocks;
    }

    return result;
}

static int vfs_jffs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
//static int dfs_jffs2_statfs(struct dfs_filesystem* fs,struct statfs *buf)
{
    /* since the limit of unsigned long, so the max size of flash device is 4G */
    struct jffs2_fs_info info;
    mtd_partition * p = (mtd_partition *)mountpt->i_private;
    int partition_num = p->patitionnum;
    JFFS_ASSERT(mte[partition_num]->data != 0);

    jffs2_get_info_from_sb((void *)mte[partition_num]->data, &info);
    buf->f_type = JFFS2_SUPER_MAGIC;
    buf->f_bsize = JFFS2_PAGE_SIZE;
    buf->f_blocks = (info.nr_blocks * info.sector_size) / JFFS2_PAGE_SIZE; /*lint !e647 */
    buf->f_bfree = info.free_size/JFFS2_PAGE_SIZE;
    buf->f_bavail = buf->f_bfree;
    buf->f_namelen = CONFIG_JFFS2_ENTRY_NAME_MAX;
    buf->f_fsid.__val[0] = JFFS2_SUPER_MAGIC;
    buf->f_fsid.__val[1] = 1;
    buf->f_frsize = 0x1000;
    buf->f_files = 0;
    buf->f_ffree = 0;
    return 0;
}


int JffsMutexCreate(void)
{
    if (LOS_MuxCreate(&jffs2_lock) != LOS_OK) {
        PRINT_ERR("%s, LOS_MuxCreate failed\n", __FUNCTION__);
        return -1;
    } else {
        return 0;
    }
}

void JffsMutexDelete(void)
{
    (VOID)LOS_MuxDelete(jffs2_lock);
}

const struct mountpt_operations jffs_operations =
{
    vfs_jffs_open,          /* open */
    vfs_jffs_close,         /* close */
    vfs_jffs_read,          /* read */
    vfs_jffs_write,         /* write */
    vfs_jffs_seek,          /* seek */
    vfs_jffs_ioctl,         /* ioctl */

    vfs_jffs_sync,          /* sync */
    vfs_jffs_dup,           /* dup */

    vfs_jffs_opendir,       /* opendir */
    vfs_jffs_closedir,      /* closedir */
    vfs_jffs_readdir,       /* readdir */

    vfs_jffs_rewinddir,     /* rewinddir */

    vfs_jffs_bind,          /* bind */
    vfs_jffs_unbind,        /* unbind */
    vfs_jffs_statfs,        /* statfs */
    NULL,                   /* virstatfs */
    vfs_jffs_unlink,        /* unlinke */
    vfs_jffs_mkdir,         /* mkdir */
    vfs_jffs_rmdir,         /* rmdir */
    vfs_jffs_rename,        /* rename */
    vfs_jffs_stat,          /* stat */
    vfs_jffs_stat64,        /* stat64 */
    NULL,                   /* for utime*/
    NULL,                   /* chattr*/
    vfs_jffs_seek64,        /* seek64 */
    NULL,                   /*getlabel*/
    NULL,                   /* fallocate Contiguous blocks */
    NULL,                   /* fallocate64 */
    NULL,                   /* truncate */
    NULL,                   /* truncate64 */
    NULL                    /* fscheck */
};


FSMAP_WOW_ENTRY(jffs_fsmap, "jffs", jffs_operations, TRUE, TRUE); /*lint !e19*/

#endif
